package com.scs.application.modules.dept.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.scs.application.consts.GlobalConsts;
import com.scs.application.consts.SerialKeys;
import com.scs.application.core.exception.BusinessException;
import com.scs.application.core.flow.FlowContext;
import com.scs.application.core.service.BaseServiceImpl;
import com.scs.application.core.utils.*;
import com.scs.application.modules.base.util.CommonService;
import com.scs.application.modules.dept.entity.*;
import com.scs.application.modules.dept.mapper.OprtUseItemMapper;
import com.scs.application.modules.dept.mapper.OprtUseMapper;
import com.scs.application.modules.dept.mapper.UseMergeMapper;
import com.scs.application.modules.dept.service.UseDtlService;
import com.scs.application.modules.dept.service.UseMergeDtlService;
import com.scs.application.modules.dept.service.UseMergeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 */
@Service
@Slf4j
public class UseMergeServiceImpl extends BaseServiceImpl<UseMergeMapper, UseMerge> implements UseMergeService {
    @Autowired
    private UseDtlService useDtlService;
    @Autowired
    private UseMergeDtlService useMergeDtlService;
    @Autowired
    private OprtUseItemMapper oprtUseItemMapper;

    @Autowired
    private OprtUseServiceImpl oprtUseService;

    @Autowired
    private OprtUseMapper oprtUseMapper;


    @Override
    @Transactional(rollbackFor = Exception.class)
    protected void afterHandleFlowChange(FlowContext flowContext, UseMerge entity) {
        super.afterHandleFlowChange(flowContext, entity);


        boolean endNode = flowContext.isEndNode();
        if (!endNode) {
            return;
        }

        //级联更新病人消耗单、记账单的审核人、审核时间
        UseMerge dbEntity = this.getById(entity.getId());


        if (dbEntity.getMergeType().equals("1")){
            if (!flowContext.getButton().getValueTo().equals("confirm")) throw  new BusinessException("结束节点，按钮操作完状态应配置为confirm，请联系运营人员进行配置");
            LocalDateTime now = LocalDateTime.now();
            List<UseMergeDtl> itemList = useMergeDtlService.list(Wrappers.<UseMergeDtl>query().in("use_merge_id", entity.getId()));
            List<String> oprtUseIds = itemList.stream().map(UseMergeDtl::getRefId).distinct().collect(Collectors.toList());
            oprtUseService.update(Wrappers.<OprtUse>update()
                    .in("id", oprtUseIds).eq("flow_status","end")
                    .set("flag_dept_audit", 1)
                    .set("dept_audit_modified", now)
                    .set("flow_modified", now)
                    .set("flow_status",flowContext.getButton().getValueTo())
                    .set("flow_modifier",UserUtils.currentUser().getName())
                    .set("dept_auditodifier", UserUtils.currentUser().getName()));

            CommonService.updatebillFlow(oprtUseIds, now,true);
        }



    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean saveByUseIds(List<Use> entityList) {
        List<String> useIds = entityList.stream().map(o -> o.getId()).collect(Collectors.toList());
        if (useIds.isEmpty()){
            throw new BusinessException("没有可用消耗单");
        }
        // 排除已经合并的消耗单明细
        List<UseDtl> useDtls = useDtlService.list(Wrappers.<UseDtl>query().in("use_id", useIds));

        String mergeId = entityList.get(0).getMergeId();
        // 创建合单明细数据
        List<UseMergeDtl> mergeDtls = useMergeDtlService.getUseMergeDtlList(useDtls, mergeId);

        // 保存合单明细
         return useMergeDtlService.saveOrUpdateBatch(mergeDtls);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean saveByOprtUseIds(List<OprtUse> entityList) {
        List<String> oprtUseIds = entityList.stream().map(o -> o.getId()).collect(Collectors.toList());
        if (oprtUseIds.isEmpty()){
            throw new BusinessException("没有可用消耗单");
        }
        // 排除已经合并的消耗单明细
        List<OprtUseItem> oprtUseItems = oprtUseItemMapper.selectList(Wrappers.<OprtUseItem>query().in("dept_oprt_use_id", oprtUseIds));

        String mergeId = entityList.get(0).getMergeId();
        // 创建合单明细数据
        List<UseMergeDtl> mergeDtls = useMergeDtlService.getUseMergeDtlListByOprt(oprtUseItems, mergeId);

        // 保存合单明细
        return useMergeDtlService.saveOrUpdateBatch(mergeDtls);
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean removeByIds(Collection<? extends Serializable> idList) {
        if (idList.isEmpty()){
            throw new BusinessException("未选择删除数据");
        }
        useMergeDtlService.remove(Wrappers.<UseMergeDtl>query().in("use_merge_id", idList));
        return super.removeByIds(idList);
    }

    @Override
    public boolean saveOrUpdate(UseMerge entity) {
        // 生成编码
        if (StringUtils.isBlank(entity.getBusKey())){
            entity.setBusKey(serialRuleAdapter.getSerialRuleService().generateCode(SerialKeys.DEPT_USE_MERGE_KEY));
        }
        return super.saveOrUpdate(entity);
    }

    @Override
    public String autoMergeOprtUseMain(String useMergeId) {

        QueryWrapper queryWrapper = Wrappers.query().eq("flow_status","end");
        String msgPre ="";

        //筛选对应合单的
        if (StringUtils.isNotBlank(useMergeId)) {
            UseMerge useMerge = this.getById(useMergeId);
            if (useMerge == null ) throw new BusinessException("消耗合单单据已被删除，请刷新页面");
            if (!GlobalConsts.FLOW_START_VALUE.equals(useMerge.getFlowStatus())) throw new BusinessException("消耗合单单据非制单状态，不允许进行合单操作");
            queryWrapper.eq("dept_id",useMerge.getDeptId());
            queryWrapper.eq("DATE_FORMAT(bus_date,'%Y-%m-%d')",DateUtils.format(useMerge.getBusDate(),"yyyy-MM-dd"));

//            queryWrapper.and(wrap ->
//                    Wrappers.query()
//                    .eq("inpatient_no",useMerge.getInpatientNo())
//                    .or().eq("outpatient_no",useMerge.getOutpatientNo())
//                    .or().eq("patient_id",useMerge.getPatientId())
//            );
            msgPre += StrUtil.format("合单条件: 科室[{}],业务日期[{}]",useMerge.getDeptName(),DateUtils.format(useMerge.getBusDate(),"yyyy-MM-dd"));
            if (StringUtils.isNotBlank(useMerge.getInpatientNo())) {
                queryWrapper.eq("inpatient_no",useMerge.getInpatientNo());
                msgPre += StrUtil.format(",住院号[{}]",useMerge.getInpatientNo());
            } else  if (StringUtils.isNotBlank(useMerge.getOutpatientNo())) {
                queryWrapper.eq("outpatient_no",useMerge.getOutpatientNo());
                msgPre += StrUtil.format(",门诊号[{}]",useMerge.getOutpatientNo());
            } else if (StringUtils.isNotBlank(useMerge.getPatientId()) && !"0".equals(useMerge.getPatientId())) {
                queryWrapper.eq("patient_id",useMerge.getPatientId());
                msgPre += StrUtil.format(",病人[{}]",useMerge.getPatientName());
            } else  {
                throw  new BusinessException("该消耗合单单据，缺少病人信息或者住院号或者门诊号，请检查");
            }
        }
        //所有可合单的病人消耗单明细
        List<OprtUseItem> oprtUseItemListAll = oprtUseItemMapper.notMergeList(queryWrapper);
        if (oprtUseItemListAll == null || oprtUseItemListAll.isEmpty()) {
            return msgPre + ",没有可以合单的病人消耗单明细";
        }

        //所有可合单的病人消耗单，只要有一条明细未合并
        List<String> deptOprtUseIdList = oprtUseItemListAll.stream().map(OprtUseItem::getDeptOprtUseId).distinct().collect(Collectors.toList());
        List<OprtUse> oprtUseListAll = oprtUseMapper.selectList(Wrappers.<OprtUse>query().in("id", deptOprtUseIdList));
        if (oprtUseListAll.isEmpty()) {
            return msgPre + ",没有可以合单的病人消耗单";
        }
        Map<String,OprtUse>  oprtUseMap= oprtUseListAll.stream().collect(Collectors.toMap(OprtUse::getId,ob -> ob));

        //病人id，门诊号，住院号全部为空的
        List<OprtUse> oprtUseIgnoreList = oprtUseListAll.stream().filter(
                ob  -> (
                        UtilCommon.getStr(ob.getPatientId(),"0").equals("0")
                        && StringUtils.isBlank(ob.getInpatientNo())
                        && StringUtils.isBlank(ob.getOutpatientNo())
                        )
        ).collect(Collectors.toList());
        String ignoreMsg ="";
        if (oprtUseIgnoreList != null && oprtUseIgnoreList.size() > 0) ignoreMsg="<br>无法合单病人消耗单数量："+oprtUseIgnoreList.size()+"，原因：门诊号或住院号或病人信息为空";



        //分组条件  业务日期，病人id，门诊号，住院号
        Map<String,List<OprtUse>> oprtUseGroupMap = oprtUseListAll.stream().filter(
                ob  -> !(
                        UtilCommon.getStr(ob.getPatientId(),"0").equals("0")
                                && StringUtils.isBlank(UtilCommon.getStr(ob.getInpatientNo(),""))
                                && StringUtils.isBlank(UtilCommon.getStr(ob.getOutpatientNo(),""))
                )
        ).collect(Collectors.groupingBy(ob -> DateUtils.format(ob.getBusDate(),"yyyy-MM-dd")+ob.getDeptId()+ob.getPatientId()+ob.getInpatientNo()+ob.getOutpatientNo()));

        if (oprtUseGroupMap == null || oprtUseGroupMap.keySet().size() < 1) {
            return msgPre + ",没有可以合单的病人消耗单" +ignoreMsg;
        }

        //手动事务
        TransactionStatus transactionStatus = null;
        int num=0,numDtl = 0;
        OprtUse oprtUseGroup;
        UseMergeDtl useMergeDtl;
        String mergeMsg ="，合单依据：业务日期+科室+病人+住院号+门诊号";
        List<UseMerge> useMergesListSave = new ArrayList<UseMerge>();
        for (List<OprtUse> oprtUseList : oprtUseGroupMap.values()) {
            try {
                //分组对象
                oprtUseGroup = oprtUseList.get(0);

                //该分组下所有病人消耗明细
                List<String> finalDeptOprtUseIdList =   oprtUseList.stream().map(OprtUse::getId).distinct().collect(Collectors.toList());
                List<OprtUseItem> oprtUseItemList = oprtUseItemListAll.stream().filter(ob -> finalDeptOprtUseIdList.contains(ob.getDeptOprtUseId())).collect(Collectors.toList());
                if (oprtUseItemList == null || oprtUseItemList.isEmpty()) continue;

                UseMerge useMerge = new UseMerge();
                useMerge.setBusDate(DateUtils.parse(DateUtils.format(oprtUseGroup.getBusDate(),"yyyy-MM-dd"),"yyyy-MM-dd"))
                        .setAmount(0d)
                        .setMergeType("1").setBusType("manual").setBusUser(UserUtils.currentUser().getName()).setBusUserCode(UserUtils.currentUser().getWorkNo())
                        .setFlagLine(true)
                        .setRemark("批量合单"+mergeMsg);
                useMerge.setDeptId(oprtUseGroup.getDeptId())
                        .setDeptName(oprtUseGroup.getDeptName())
                        .setInpatientNo(oprtUseGroup.getInpatientNo())
                        .setOutpatientNo(oprtUseGroup.getOutpatientNo())
                        .setPatientName(oprtUseGroup.getPatientName()).setPatientId(oprtUseGroup.getPatientId());
                if (useMerge.getBusUser().equals("系统")) {
                    useMerge.setBusType("auto").setRemark("系统自动合单"+mergeMsg);
                }
                if (StringUtils.isNotBlank(useMergeId))  useMerge.setId(useMergeId);

                //开启手动事务
                transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
                this.saveOrUpdate(useMerge);

                // 过滤已合并消耗单 获取合单明细
                List<UseMergeDtl> mergeDtls = new ArrayList<>();
                for (OprtUseItem oprtUseItem : oprtUseItemList) {
                    OprtUse oprtUseDb = oprtUseMap.get(oprtUseItem.getDeptOprtUseId());
                    useMergeDtl = new UseMergeDtl();
                    useMergeDtl.setUseMergeId(useMerge.getId()).setRefItemId(oprtUseItem.getId()).setRefId(oprtUseItem.getDeptOprtUseId())
                            .setRefTable("dept_oprt_use").setStockId(oprtUseItem.getStockId())
                            .setMatrId(oprtUseItem.getMatrId()).setMatrName(oprtUseItem.getMatrName()).setMatrSpec(oprtUseItem.getMatrSpec())
                            .setPackageQty(oprtUseItem.getPackageQty()).setPackageUnit(oprtUseItem.getPackageUnit())
                            .setSkuPrice(oprtUseItem.getSkuPrice()).setSkuQty(oprtUseItem.getSkuQty()).setAmount(oprtUseItem.getAmount())
                            .setLot(oprtUseItem.getLot()).setExpDate(oprtUseItem.getExpDate()).setSnNo(oprtUseItem.getSn())
                            .setRfid(oprtUseItem.getRfid()).setRemark("人工合单")
                            .setUser(oprtUseDb.getFlowModifier()).setUseTime(oprtUseDb.getBusDate());
                    mergeDtls.add(useMergeDtl);
                }
                useMergeDtlService.saveBatch(mergeDtls);
                numDtl = mergeDtls.size();

                //刷新主表金额
                    Double totalAmount = calcMergeAmount(useMerge.getId());
                    useMerge.setAmount(totalAmount);
                    this.updateCascadeById(useMerge);

                //手动事务提交
                dataSourceTransactionManager.commit(transactionStatus);
                num++;
                useMergesListSave.add(useMerge);
            }catch (Exception e) {
                log.error("UseMergeServiceImpl.autoMergeOprtUseMain.error",e);
                //手动事务回滚
                try {
                    dataSourceTransactionManager.rollback(transactionStatus);
                }catch (Exception e1) {
                    log.error("UseMergeServiceImpl.autoMergeOprtUseMain.rollbackerror",e1);
                }
            }
        }

        //定时任务触发的合单发送站内信到admin、运营主管、对应消耗科室
        if (useMergesListSave.size() > 0 && "系统".equals(UserUtils.currentUser().getName())) {
            List<String> deptIdList = useMergesListSave.stream().map(UseMerge::getDeptId).distinct().collect(Collectors.toList());
            String msg = String.format("新增合单单据：%s<br>涉及消耗科室：%s",useMergesListSave.size(),deptIdList.size());
            //推送消息给运营管理员 和管理员
            CommonService.pushMessageRole("病人消耗自动合单",msg , "admin_yy,admin");

            //推送消息给对应科室
            deptIdList.stream().forEach(deptId -> {
                List<UseMerge> useMergesListSaveDept = useMergesListSave.stream().filter(ob -> deptId.equals( ob.getDeptId())).collect(Collectors.toList());
                long patientNum = useMergesListSaveDept.stream().map(ob -> ob.getInpatientNo()+ob.getOutpatientNo()+ob.getPatientId()).distinct().count();
                String msg2 = String.format("新增合单单据：%s<br>涉及病人：%s",useMergesListSaveDept.size(),patientNum);
                CommonService.pushMessageDept("病人消耗自动合单", msg2, deptId);
            });
            return msg;
        }

        if (StringUtils.isNotBlank(useMergeId)) {
            return msgPre + ",增加明细："+numDtl+ignoreMsg;
        }
        return msgPre + ",新增合并单据："+num+ignoreMsg;
    }

    private Double calcMergeAmount(String useMergeId) {
        //合单明细
        List<UseMergeDtl> useMergeDtlList = useMergeDtlService.list(Wrappers.<UseMergeDtl>query().eq("use_merge_id" , useMergeId));
        if (useMergeDtlList == null || useMergeDtlList.size() < 1) return 0d;

        List<String> refIdNullList = useMergeDtlList.stream().filter(ob -> StringUtils.isBlank(ob.getRefId())).map(UseMergeDtl::getRefId).collect(Collectors.toList());
        if (refIdNullList != null && refIdNullList.size() > 1) throw  new BusinessException("自动合单失败，合单明细关联ID为空，数量%s",refIdNullList.size());
        List<String> refIdList = useMergeDtlList.stream().map(UseMergeDtl::getRefId).distinct().collect(Collectors.toList());

        //关联病人消耗单
        List<OprtUse> oprtUseListAll = oprtUseMapper.selectList(Wrappers.<OprtUse>query().in("id", refIdList));
        if (oprtUseListAll == null || oprtUseListAll.size() < 1) throw  new BusinessException("自动合单失败，合单明细关联ID都未找到原始单据，数量%s",refIdList.size());
        if (refIdList.size() != oprtUseListAll.size()) throw  new BusinessException("自动合单失败，合单明细关联数量与原始单据数量不匹配，关联数量%s，实际数量%s",refIdList.size(),oprtUseListAll.size());

        List<OprtUse> oprtUseErrorListAll=oprtUseListAll.stream().filter(ob -> ob.getFlagUseRedType() != 0 && ob.getFlagUseRedType() != 1).collect(Collectors.toList());
        if (oprtUseErrorListAll != null && oprtUseErrorListAll.size() > 0) throw  new BusinessException("自动合单失败，合单明细关联原始单据状态错误，数量%s",oprtUseErrorListAll.size());

        //病人消耗单-计费
        Map<String,OprtUse> oprtUseBillMap = oprtUseListAll.stream().filter(ob -> ob.getFlagUseRedType() == 0).collect(Collectors.toMap(OprtUse::getId, OprtUse -> OprtUse));
        //病人消耗单-退费
        Map<String,OprtUse> oprtUseUnbillMap = oprtUseListAll.stream().filter(ob -> ob.getFlagUseRedType() == 1).collect(Collectors.toMap(OprtUse::getId, OprtUse -> OprtUse));

        //计费明细
        double amoutBill = useMergeDtlList.stream().filter(ob -> oprtUseBillMap.containsKey(ob.getRefId())).mapToDouble(UseMergeDtl::getAmount).sum();


        //退费明细
        List<UseMergeDtl> useMergeDtlUnBillList = useMergeDtlList.stream().filter(ob -> oprtUseUnbillMap.containsKey(ob.getRefId())).collect(Collectors.toList());
        double amoutUnBill = 0d;
        if (useMergeDtlUnBillList != null && useMergeDtlUnBillList.size() > 0) {
            //合计金额取绝对值，存在历史数据，可能有正有负数
            amoutUnBill = useMergeDtlUnBillList.stream().mapToDouble(ob -> Math.abs(ob.getAmount())).sum();

            //退费明细 金额改为负数
            List<UseMergeDtl> useMergeDtlUnBillAmountErrorList = useMergeDtlUnBillList.stream().filter(ob -> ob.getAmount() >0).collect(Collectors.toList());
            if (useMergeDtlUnBillAmountErrorList != null && useMergeDtlUnBillAmountErrorList.size() > 0) {
                for(UseMergeDtl useMergeDtl : useMergeDtlUnBillAmountErrorList) {
                    useMergeDtl.setAmount(-useMergeDtl.getAmount());
            }
                useMergeDtlService.updateBatchById(useMergeDtlUnBillAmountErrorList);
    }

}
        return UtilNum.sub(amoutBill, amoutUnBill);
    }
}
